﻿// Bravura : A music composition and audio synthesis framework.
//
// Copyright © 2011 Paul Vanukoff (pvanukoff@gmail.com)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.

using Bravura.Contracts.Directives;
using Bravura.Core.MusicLib;

namespace Bravura.Contracts.Modifiers
{
	/// <summary>
	/// Modifies the Voice, Sound, Pitch, Velocity, NoteOn or NoteOff values of a Note directive.
	/// </summary>
	public class NoteModifier : IModifier
	{
		#region Properties

		/// <summary>
		/// Added to Voice value of target Note.
		/// </summary>
		public int VoiceShift
		{
			get;
			set;
		}

		/// <summary>
		/// Added to Sound value of target Note.
		/// </summary>
		public double? SoundChange
		{
			get;
			set;
		}

		/// <summary>
		/// Added to Pitch value of target Note.
		/// </summary>
		public double? PitchChange
		{
			get;
			set;
		}

		/// <summary>
		/// Multipled with Velocity value of target Note.
		/// </summary>
		public double? VelocityChange
		{
			get;
			set;
		}

		/// <summary>
		/// Adjusts the time of each note-on by a fixed amount.
		/// </summary>
		public int NoteOnDelay
		{
			get;
			set;
		}

		/// <summary>
		/// Adjusts the time of each note-off by a fixed amount.
		/// </summary>
		public int NoteOffDelay
		{
			get;
			set;
		}

		/// <summary>
		/// Additional settings to apply on note-on.
		/// </summary>
		public NoteSettingList NoteOnSettings
		{
			get;
			set;
		}

		/// <summary>
		/// Additional controls to apply on note-on.
		/// </summary>
		public NoteControlList NoteOnControls
		{
			get;
			set;
		}

		#endregion

		#region IModifier

		IDirective IModifier.Modify(IDirective input)
		{
			IDirective output = input;

			if (input is Note)
			{
				Note target = input as Note;

				Note copy = new Note();

				copy.Voice = target.Voice + this.VoiceShift;
				copy.Sound = target.Sound.HasValue && this.SoundChange.HasValue ? target.Sound + this.SoundChange : target.Sound;
				copy.Pitch = target.Pitch.HasValue && this.PitchChange.HasValue ? target.Pitch + this.PitchChange : target.Pitch;
				copy.Velocity = target.Velocity.HasValue && this.VelocityChange.HasValue ? target.Velocity * this.VelocityChange : target.Velocity;
				copy.NoteOnTime = target.NoteOnTime + this.NoteOnDelay;
				copy.NoteOffTime = target.NoteOffTime + this.NoteOffDelay;

				copy.NoteOnControls = new NoteControlList();
				copy.NoteOnControls.AddRange(target.NoteOnControls);
				copy.NoteOnControls.AddRange(this.NoteOnControls);

				copy.NoteOnSettings = new NoteSettingList();
				copy.NoteOnSettings.AddRange(target.NoteOnSettings);
				copy.NoteOnSettings.AddRange(this.NoteOnSettings);

				output = copy;
			}

			return output;
		}

		#endregion
	}
}
